<?php

namespace app\zyhsapi\model;

use app\chat\LiveMessage;
use app\common\cachemodel\consult\AppUserConsultGift;
use app\common\cachemodel\consult\AppUserConsultGiftUseRecord;
use app\common\cachemodel\OrdersLib;
use app\common\cachemodel\UserCoupon;
use app\common\cachemodel\ZhunleUserAccount;
use app\common\cachemodel\ZhunleUserAccountRecord;
use app\common\cachemodel\zlcr3\Zlcr3ConsultAccount;
use app\common\cachemodel\ZlcrAstr;
use app\common\cachemodel\ZlcrAstrAccount;
use app\common\lib\Util;
use app\common\model\User;
use think\Db;
use think\Env;
use think\Log;
use XznsTools\cache\zyhs\CacheManageZyhs;

class ZyhsConsultChatRtcRecord extends BaseCacheZyhs
{
    protected $table = 'good_wechat.zyhs_consult_chat_rtc_record';

    protected $cacheModel = 'voice_consult.chat_rtc';

    /**
     * 用户咨询列表
     * @param int $appType
     * @param int $uid
     * @return array|mixed
     * @throws \Exception
     */
    public function userRtcChat(int $appType, int $uid)
    {
        $data = $this->getListPage($uid, 'id', [], $appType);
        $astrIds = array_values(array_unique(array_column($data['data'], 'astr_id')));
        $astrInfos = (new ZlcrAstr())->batchGetInfoByIds($astrIds, ['nickname', 'avatar', 'extend']);
        $res = [];
        foreach ($data['data'] as $item)
        {
            $res[] = [
                'id' => (int)($item['chat_detail_id'] ?? 0),
                'avatar' => $astrInfos[$item['astr_id']]['avatar'],
                'name' => $astrInfos[$item['astr_id']]['nickname'],
                'list' => [
                    [
                        'title' => '服务编号',
                        'des' => $item['chat_detail_id'] ?? 0,
                        'type' => 2,
                    ],
                    [
                        'title' => '连线时长',
                        'des' => gmdate("H:i:s", $item['duration']),
                        'type' => 1,
                    ],
                    [
                        'title' => '连线消耗',
                        'des' => $item['coin'] . '准币',
                        'type' => 1,
                    ],
                    [
                        'title' => '接通时间',
                        'des' => date('Y-m-d H:i:s', $item['start_time']),
                        'type' => 1,
                    ],
                ],
            ];
        }
        $data['data'] = $res;
        return $data;
    }

    /**
     * 获取 连线咨询 服务列表
     * @param int $appType
     * @param int $uid
     * @return array
     * @throws \Exception
     */
    public function getRtcServiceList(int $appType, int $uid)
    {
        $data = $this->getListPage($uid, 'id', [], $appType);
        $astrIds = array_values(array_unique(array_column($data['data'], 'astr_id')));
        $astrInfos = (new ZlcrAstr())->batchGetInfoByIds($astrIds, ['nickname', 'avatar', 'extend']);
        $res = [];
        $oss = Env::get('host.photo');
        foreach ($data['data'] as $item)
        {
            $durationTime = Util::secondToMinute($item['duration']);

            $res[] = [
                'id' => (int)($item['id'] ?? 0),
                'avatar' => $astrInfos[$item['astr_id']]['avatar'] ? $oss . $astrInfos[$item['astr_id']]['avatar'] : $oss . '/zyhsapp/default_avatar.png',
                'name' => $astrInfos[$item['astr_id']]['nickname'],
                'list' => [
                    [
                        'name' => '服务编号',
                        'value' => $item['chat_detail_id'] ?? 0,
                    ],
                    [
                        'name' => '连线时长',
                        'value' => $durationTime,
                    ],
                ],
            ];
        }
        $data['data'] = $res;
        return $data;
    }

    /**
     *  写入 连线数据
     * @param $data
     * @return int
     */
    public function SaveData($data)
    {
        try
        {
            if (isset($data['extend']))
            {
                $data['extend'] = json_encode($data['extend'], JSON_UNESCAPED_UNICODE);
            }

            $id = $this->insertGetId($data);

            return (int)$id;
        }
        catch (\Exception $e)
        {
            \think\Log::write(__CLASS__ . ' => ' . __FUNCTION__ . '()异常：' . $e->getMessage() . '失败信息：' . $e->getFile() . ':' . $e->getLine(), 'error', true);
            return 0;
        }
    }

    /**
     * 更新 RTC 信息
     * @param int $id
     * @param int $appType 1=>准有好事 2=>准了APP
     * @param int $uid
     * @param array $data
     * @param int $actionType 操作类型 1=>更新消耗准币信息｜连麦状态  2=>挂断
     * @return bool
     */
    public function updateData(int $id, int $appType, int $uid, array $data, int $actionType)
    {
        try
        {   //
            if (isset($data['extend']))
            {
                $data['extend'] = json_encode($data['extend'], JSON_UNESCAPED_UNICODE);
            }

            if (isset($data['voice_extend']))
            {
                $data['voice_extend'] = json_encode($data['voice_extend'], JSON_UNESCAPED_UNICODE);
            }

            $this->where(['id' => $id])->update($data);

            if ($actionType === 2)
            {   // 挂断的时候 添加到连线列表
                $this->listDataAdd($uid, [$id => $id], $appType);
            }
            CacheManageZyhs::getInstance()->setCacheConfig($this->cacheModel, $id)->setCacheTime(3)->setCache($data);
            return true;
        }
        catch (\Exception $e)
        {
            \think\Log::write(__CLASS__ . ' => ' . __FUNCTION__ . '()异常：' . $e->getMessage() . '失败信息：' . $e->getFile() . ':' . $e->getLine(), 'error', true);
            return false;
        }
    }

    /**
     * @param array $ids
     * @param array|null $type
     * @param string $sortType
     * @return array
     */
    public function getInfoByIdsInData($ids, $type, $sortType)
    {
        if ($ids)
        {   // 获取未删除 的数据
            $where = ['id' => ['in', $ids]];
        } else
        {   // 获取指定pid  未删除 且 未隐藏的数据
            $where = ['app_type' => $type[1], 'uid' => $type[0]];
        }
        $field = 'app_type,uid,chat_detail_id,astr_id,status,type,is_recommend,is_comment,duration,test_duration,eff_duration,unit_price,coin,astr_earning,extend,create_time,start_time,end_time';
        try
        {
            $data = $this
                ->field($field)
                ->where($where)
                ->column($field, 'id');
        }
        catch (\Exception $e)
        {
            $data = [];
        }
        return $data;
    }

    public function batchGetInfoByIds($cids, $field = [])
    {
        $resData = parent::batchGetInfoByIds($cids, $field);

        return $this->dataInit($resData);
    }

    /**
     * 数据初始化
     * @param array $data
     * @return array
     */
    public function dataInit(array $data)
    {
        foreach ($data as $index => $itemData)
        {
            $data[$index] = arrayKeyData2int($itemData, ['id', 'chat_detail_id', 'astr_id', 'app_type', 'uid', 'status', 'type', 'duration', 'is_recommend', 'is_comment', 'test_duration', 'eff_duration', 'unit_price', 'coin', 'create_time', 'start_time', 'end_time']);

            if (isset($itemData['extend']))
            {
                $data[$index]['extend'] = $itemData['extend'] ? json_decode($itemData['extend'], true) : [];
            }
        }

        return $data;
    }

    /**
     * 保存当前连麦数据 到缓存
     * @param int $type 1 =>用户   2=>占星师
     * @param int $appType 1=>准有好事 2=>准了APP
     * @param int $id
     * @param array $data
     * @param bool $isUpdate
     * @param int $chatDetailId
     * @return bool
     */
    public function saveNowRtcDataToCache(int $type, int $appType, int $id, array $data, bool $isUpdate = false, int $chatDetailId = 0)
    {
        try
        {
            if (isset($data['recode_datas']))
            {
                $data['recode_datas'] = json_encode($data['recode_datas'], JSON_UNESCAPED_UNICODE);
            }

            if (isset($data['dice_datas']))
            {
                $data['dice_datas'] = json_encode($data['dice_datas'], JSON_UNESCAPED_UNICODE);
            }

            if (isset($data['tarot_datas']))
            {
                $data['tarot_datas'] = json_encode($data['tarot_datas'], JSON_UNESCAPED_UNICODE);
            }
            // $cacheId = ($type === 1 ? 'user:' : 'astro:') . $id;
            // CacheManageZyhs::getInstance()->setCacheConfig($this->cacheModel)->setCacheKeyDetail('now_rtc', $cacheId)->setCache($data, 'now_rtc', $isUpdate);
            // 使用 新模式  【数据库 +  redis】
            (new ZyhsConsultChatRtcRecordNow())->saveNowRtcDataToCacheAndDB($type, $appType, $id, $data, $chatDetailId, $isUpdate);
        }
        catch (\Exception $e)
        {
            Log::write('更新当前咨询连麦数据 到缓存失败:' . $e->getMessage(), 'error');
            return false;
        }

        return true;
    }

    /**
     * 从缓存中 获取当前连麦数据
     * @param int $type 1 =>用户   2=>占星师 【获取占星师连麦数据时  APP_TYPE 字段无效】
     * @param int $appType 1=>准有好事 2=>准了APP
     * @param int $id
     * @param array $filed
     * @return bool|array|string
     */
    public function getNowRtcDataByCache(int $type, int $appType, int $id, array $filed = [])
    {
        try
        {
            // $cacheId = ($type === 1 ? 'user:' : 'astro:') . $id;
            // $data = CacheManageZyhs::getInstance()->setCacheConfig($this->cacheModel)->setCacheKeyDetail('now_rtc', $cacheId)->getCache($filed, 'now_rtc');
            // 使用 新模式  【数据库 +  redis】
            $data = (new ZyhsConsultChatRtcRecordNow())->getNowRtcDataByCache($type, $appType, $id, $filed);

            if ($data)
            {
                $data = arrayKeyData2int($data, ['id', 'app_type', 'astr_id', 'gift_id', 'uid', 'status', 'request_time', 'chat_id', 'user_rtc_online', 'astr_rtc_online']);

                if (isset($data['recode_datas']))
                {
                    $data['recode_datas'] = $data['recode_datas'] ? json_decode($data['recode_datas'], true) : [];
                }

                if (isset($data['dice_datas']))
                {
                    $data['dice_datas'] = $data['dice_datas'] ? json_decode($data['dice_datas'], true) : [];
                }

                if (isset($data['tarot_datas']))
                {
                    $data['tarot_datas'] = $data['tarot_datas'] ? json_decode($data['tarot_datas'], true) : [];
                }
                if (!isset($data['app_type']))
                {
                    $data['app_type'] = 1;
                }
            }

            return $data;
        }
        catch (\Exception $e)
        {
            Log::write('获取当前咨询连麦数据 到缓存失败:' . $e->getMessage(), 'error');
            return false;
        }
    }

    /**
     * 从缓存中 删除当前连麦数据
     * @param int $type 1 =>用户   2=>占星师
     * @param int $appType 1=>准有好事 2=>准了APP
     * @param int $id
     * @param int $chatDetailId
     * @return bool
     */
    public function delNowRtcDataByCache(int $type, int $appType, int $id, int $chatDetailId)
    {
        try
        {
            // $cacheId = ($type === 1 ? 'user:' : 'astro:') . $id;
            // CacheManageZyhs::getInstance()->setCacheConfig($this->cacheModel)->setCacheKeyDetail('now_rtc', $cacheId)->rmCache('now_rtc');
            // 使用 新模式  【数据库 +  redis】
            (new ZyhsConsultChatRtcRecordNow())->delNowRtcDataByCacheAndDB($type, $appType, $id, $chatDetailId);
        }
        catch (\Exception $e)
        {
            Log::write('删除咨询当前连麦数据 到缓存失败:' . $e->getMessage(), 'error');
            return false;
        }
        return true;
    }

    /**
     * 获取 RTC 操作 加锁 2秒的锁
     * @param int $chatDetailId
     * @return bool 加锁成功=>true    加锁失败=>false   加锁成功允许进行后续操作 否则禁止进行后续操作
     * @throws \RedisException
     */
    public function setRtcPadlock(int $chatDetailId, string $type = '')
    {
        if ($type)
        {
            $key = $type . ':' . $chatDetailId;
        } else
        {
            $key = $chatDetailId;
        }
        $cache = CacheManageZyhs::getInstance()->setCacheConfig($this->cacheModel)->setCacheKeyDetail('rtc_padlock', $key);
        $redis = $cache->redisHandler;

        $num = $redis->incr($cache->cacheKey['rtc_padlock']);
        if ($num === 1)
        {
            $redis->expire($cache->cacheKey['rtc_padlock'], 3);
            return true;
        } else
        {
            return false;
        }
    }

    /**
     * 删除之前 加的锁
     */
    public function loseOperatorLicense(int $chatDetailId, string $type = '')
    {
        if ($type)
        {
            $key = $type . ':' . $chatDetailId;
        } else
        {
            $key = $chatDetailId;
        }
        CacheManageZyhs::getInstance()->setCacheConfig($this->cacheModel)->setCacheKeyDetail('rtc_padlock', $key)->rmCache('rtc_padlock');
    }

    /**
     * @param array $astrNowConsultRtcInfo
     * @param int $type 1=>获取用户端显示信息 2=>获取咨询师端显示信息
     * @return array[]
     */
    public function resetRtcConsultStatusData(array $astrNowConsultRtcInfo, int $type = 1)
    {
        $recodeDatas = $astrNowConsultRtcInfo['recode_datas'] ?? [];
        foreach ($recodeDatas as $k => $recodeItemData)
        {
            if ($type === 2)
            {
                $recodeDatas[$k]['comments'] = $recodeItemData['user_des'];
            }
            unset($recodeDatas[$k]['user_des']);
        }
        // 华为 或者 oppo 或者 荣耀
        $isHuaweiOrOppo = Util::IsHuaweiAndOppo() || Util::IsHonor();
        return [
            [
                'type' => 1,
                'icon' => '/test/rtc_consult/astr_icon.png',
                'title' => '星盘',
                'des' => '根据咨询师的要求提供档案',
                'recode_datas' => $recodeDatas,
            ], [
                'type' => 2,
                'icon' => '/test/rtc_consult/dice_icon.png',
                'title' => '骰子',
                'des' => '根据咨询师的要求掷出骰子',
                'dice_datas' => $astrNowConsultRtcInfo['dice_datas'] ?? [],
            ], [
                'type' => 3,
                'icon' => '/test/rtc_consult/tarot_icon.png',
                'title' => $isHuaweiOrOppo ? '卡牌' : '塔罗',
                'des' => '根据咨询师的要求抽取' . ($isHuaweiOrOppo ? '卡牌' : '塔罗牌'),
                'tarot_datas' => $astrNowConsultRtcInfo['tarot_datas'] ?? [],
            ],
        ];
    }

    /**
     * RTC 连线咨询 挂断
     * @param array $chatDetail
     * @param string $reason 故障挂断 原因
     * @param int $userType 挂断用户  1=>用户 2=>咨询师
     * @param int $hangUpType 挂断类型 1=>主动挂断【 用户｜咨询师 主动挂断 】 2=>被动挂断【 rtc离线 】 3=>被动挂断【 队列扣费准币不足 】
     * @return array
     * @throws \Exception
     */
    public function rtcConsultHangUp(array $chatDetail, string $reason, int $userType = 1, int $hangUpType = 1): array
    {
        $chatDetailId = $chatDetail['id'];
        for ($i = 0; $i <= 20; $i++)
        {   // 加锁
            $res = $this->setRtcPadlock($chatDetailId, 'HangUp');
            if ($res)
            {
                break;
            }
            usleep(500000);
        }
        if (!$res)
        {
            return ['status' => false, 'data' => [], 'msg' => '连线状态异常',];
        }

        $nowTime = time();
        // 挂断
        $rtcInfo = $this->getInfoById($chatDetail['extend']['rtc_data']['rtc_id'], ['status', 'app_type', 'uid', 'extend', 'astr_id', 'unit_price', 'start_time', 'coin', 'test_duration', 'id', 'create_time', 'type', 'chat_detail_id', 'astr_earning', 'duration']);
        if (in_array($rtcInfo['status'], [4, 5, 6], true))
        {
            return ['status' => false, 'data' => [], 'msg' => '连线已挂断',];
        }
        $appType = $rtcInfo['app_type'] ?? 1;
        if ($appType === 1)
        {   // 准有好事
            $UserAccountModel = new ZyhsUserAccount();
            $UserAccountRecordModel = new ZyhsUserAccountRecord();
            $websocketWho = LiveMessage::WHO_TYPE_ZYHS_UID;
            $userCouponModel = new ZyhsUserCoupon();
            $userInfo = (new ZyhsUser())->getInfoById($rtcInfo['uid'], ['avatar']);
        } else
        {   // 准了APP
            $UserAccountModel = new ZhunleUserAccount();
            $UserAccountRecordModel = new ZhunleUserAccountRecord();
            $websocketWho = LiveMessage::WHO_TYPE_UID;
            $userCouponModel = new UserCoupon();
            $userInfo = (new User())->getUserinfo(['id' => $rtcInfo['uid']]);
        }
        $rtcInfoUpdate = [
            'type' => 2,
            'end_time' => $nowTime,
            'extend' => $rtcInfo['extend'],
            'duration' => 0,
        ];
        $zlcr3ConsultAccountModel = new Zlcr3ConsultAccount();
        $consultAccountInfo = $zlcr3ConsultAccountModel->getInfoById($rtcInfo['astr_id']);
        $eventMarkingData = [
            'astr_id' => $rtcInfo['astr_id'],
            'tags' => $zlcr3ConsultAccountModel->getTags($consultAccountInfo['tags']),   // 技能标签
            'unit_price' => ceil($rtcInfo['unit_price'] * $rtcInfo['extend']['active_percent']), // 服务单价
            'coupon_id' => 0,  // 优惠券ID
            'line_duration' => 0,  // 连线时长【秒】
            'service_num' => $chatDetailId,    // 服务编号
            'coin_used' => 0,  // 使用准币数
            'end_type' => '',   // 挂断方式【故障挂断｜主动挂断（占星师或用户主动挂断）｜自动挂断（准币不足自动挂断）】
            'rebuy_num' => $rtcInfo['extend']['service_num'],   // 复购次数
        ];
        if ($rtcInfo['status'] === 2)
        {   // 连接中
            $rtcInfoUpdate['status'] = 6;
        } else
        {   // 语音咨询中
            $duration = $nowTime - $rtcInfo['start_time'];
            if ($duration < 60)
            {
                if ($hangUpType === 1 && empty($reason))
                {
                    return ['status' => false, 'data' => [], 'msg' => '请选择故障挂断原因～',];
                }
                $rtcInfoUpdate['status'] = 5;
                $rtcInfoUpdate['extend']['reason'] = $reason;   // 故障挂断原因
                $eventMarkingData['end_type'] = '故障挂断';
            } else
            {
                $rtcInfoUpdate['status'] = 4;
                $eventMarkingData['end_type'] = $hangUpType === 1 ? '主动挂断' : "被动挂断";
            }
            $rtcInfoUpdate['duration'] = $duration;
            $eventMarkingData['line_duration'] = $duration;
        }
        // 获取咨询师 当前连麦状态
        $astrNowConsultRtcInfo = $this->getNowRtcDataByCache(2, $appType, $rtcInfo['astr_id']);
        if ($astrNowConsultRtcInfo && $astrNowConsultRtcInfo['chat_id'] == $chatDetailId)
        {   // 咨询师 当前连麦 与当前取消的连麦是一致的
            // 记录 咨询信息
            $rtcInfoUpdate['extend']['recode_datas'] = $astrNowConsultRtcInfo['recode_datas'] ?? [];
            $rtcInfoUpdate['extend']['dice_datas'] = $astrNowConsultRtcInfo['dice_datas'] ?? [];
            $rtcInfoUpdate['extend']['tarot_datas'] = $astrNowConsultRtcInfo['tarot_datas'] ?? [];
            // 删除 当前咨询 信息
            $this->delNowRtcDataByCache(2, $appType, $rtcInfo['astr_id'], $chatDetailId);
        }
        $isCustomer = false;
        if ($rtcInfoUpdate['status'] === 4)
        {   // 正常挂断
            $totalAmount = $rtcInfo['coin'] / 10;
            $userCoin = $UserAccountModel->getUserCoinFromCache($rtcInfo['uid']);  // 账户信息
            $coinNum = (int)($userCoin['balance'] ?? 0);// 准币余额
            $useCoinNum = 0;
            $giftRtcPrice = 0;
            if ($rtcInfoUpdate['duration'] - $rtcInfo['test_duration'] > 0)
            {   // 获取使用的优惠券
                if ($hangUpType === 3)
                {
                    $t = $rtcInfoUpdate['duration'] % 60;
                    if ($t < 10)
                    {   // 连线时长更新
                        $rtcInfoUpdate['duration'] = $rtcInfoUpdate['duration'] - $t;
                    }
                }
                $freeRtcDuration = $rtcInfo['extend']['free_rtc_duration'] ?? 0; // 免费连线时长
                $freeRtcDuration = max($freeRtcDuration, $rtcInfo['test_duration']);    // 免费连线时长
                $giftId = $rtcInfo['extend']['gift_id'] ?? 0;
                // 本次连线收费   判断是否使用优惠券   // 礼包与礼券不可同时使用
                $useCouponInfo = $rtcInfoUpdate['duration'] > $freeRtcDuration && $giftId === 0 ? $userCouponModel->getConsultUseCouponInfo($rtcInfo['uid'], ceil($rtcInfoUpdate['duration'] / 60)) : null;
                $unitPrice = ceil($rtcInfo['unit_price'] * $rtcInfo['extend']['active_percent']);
                if ($useCouponInfo)
                {   // 使用优惠券 情况 计价时长
                    $effDuration = $rtcInfoUpdate['duration'] - $freeRtcDuration - ($useCouponInfo['discount'] * 60);
                    $rtcInfoUpdate['eff_duration'] = max($effDuration, 0);  // 计价时长
                    if ($rtcInfoUpdate['eff_duration'] > 0)
                    {   // 计价分钟
                        $effMin = ceil($rtcInfoUpdate['eff_duration'] / 60);
                        // 获取本次 连线 消耗准币 数量
                        $useCoinNum = $effMin * $unitPrice; // 本次连线 实际应收准币 数量
                    }
                    $diffCoin = $rtcInfo['coin'] - $useCoinNum; // 获取 使用优惠后 需要更新的差值准币
                    $rtcInfoUpdate['coin'] = $useCoinNum;
                    $rtcInfo['coin'] = $useCoinNum;
                    $totalAmount = $useCoinNum / 10;
                    // 更新用户准币余额
                    $coinNum = $coinNum + $diffCoin;
                    $consume_price = $userCoin['consume_price'] - OrdersLib::getOrderCoinTotalAmount($diffCoin);
                    $consume_coin = $userCoin['consume_coin'] - $diffCoin;
                    //更新用户钱包金额
                    $UserAccountModel->UpdateData($rtcInfo['uid'], ['balance' => $coinNum, 'consume_price' => $consume_price, 'consume_coin' => $consume_coin, 'update_time' => time()], ['uid' => $rtcInfo['uid']]);
                    // 记录 使用优惠券
                    $rtcInfoUpdate['extend']['cid'] = $useCouponInfo['id'];
                    if ($appType === 1)
                    {   // 准有好事 使用优惠券
                        $userCouponModel->use_return($rtcInfo['uid'], $useCouponInfo['id'], ['status' => 1, 'rtc_id' => $rtcInfo['id'], 'update_time' => $nowTime]);   // oid 存储连线ID
                    } else
                    {   // 准了APP 使用优惠券
                        $userCouponModel->use_return($rtcInfo['uid'], $useCouponInfo['id'], ['status' => 1, 'oid' => $rtcInfo['id'], 'update_time' => $nowTime]);   // oid 存储连线ID
                    }
                    // 打点数据 使用优惠券ID
                    $eventMarkingData['coupon_id'] = $useCouponInfo['id'];
                } else
                {   // 计价时长
                    $effDuration = $rtcInfoUpdate['duration'] - $freeRtcDuration;
                    $effDuration = max($effDuration, 0);
                    //  礼包可用时长
                    if ($effDuration > 0 && $giftId)
                    {
                        $appUserConsultGiftModel = new AppUserConsultGift();
                        $userGiftInfo = $appUserConsultGiftModel->getInfoById($giftId);
                        $giftDuration = ($userGiftInfo['duration_minute'] - $userGiftInfo['use_minute']) * 60;
                        $giftUseDuration = min($effDuration, $giftDuration); // 礼包使用时长
                        $giftUseDurationMin = ceil($giftUseDuration / 60);  // 礼包使用分钟
                        $giftRtcPrice = $userGiftInfo['unit_price'] * $giftUseDurationMin;   // 连线礼包收入
                        // 连线咨询 礼包 使用 ------------------------------------------
                        $giftUpdateData = [
                            'use_minute' => $userGiftInfo['use_minute'] + $giftUseDurationMin,  //  礼包已使用 - 分钟
                            'update_time' => $nowTime,  // 更新时间
                        ];
                        if ($userGiftInfo['status'] === 1)
                        {   // 礼包 使用中
                            if ($userGiftInfo['duration_minute'] <= $giftUpdateData['use_minute'])
                            {   //  礼包已用尽
                                $giftUpdateData['status'] = 2;  // 已用尽
                            } elseif ($userGiftInfo['end_time'] > 0 && $userGiftInfo['end_time'] < $nowTime)
                            {
                                $giftUpdateData['status'] = 3;  // 已过期
                            }
                        }
                        // 写入 礼包使用记录
                        (new AppUserConsultGiftUseRecord())->saveData([
                            'uid' => $rtcInfo['uid'],
                            'ug_id' => $giftId, // 用户礼包ID【app_user_consult_gift】
                            'rtc_id' => $rtcInfo['id'], // 连线咨询ID【good_wechat.zyhs_consult_chat_rtc_record】
                            'chat_detail_id' => $chatDetailId, //good_wechat.zyhs_consult_chat_record_details对话记录表ID
                            'create_time' => $nowTime,
                            'use_min' => $giftUseDurationMin,
                            'use_time' => $rtcInfo['create_time'],   // 使用时间 记录的是发起连线时间
                        ]);
                        // 更新 礼包信息
                        $appUserConsultGiftModel->updateData($rtcInfo['uid'], $giftId, $giftUpdateData);
                    } else
                    {
                        $giftUseDuration = 0;
                    }
                    $rtcInfoUpdate['extend']['gift_use_duration'] = $giftUseDuration;   // 礼包使用时长
                    $effDuration = $effDuration - $giftUseDuration;
                    $rtcInfoUpdate['eff_duration'] = max($effDuration, 0);  // 计价时长
                    if ($rtcInfoUpdate['eff_duration'] > 0)
                    {   // 计价分钟
                        $effMin = ceil($rtcInfoUpdate['eff_duration'] / 60);
                        // 获取本次 连线 消耗准币 数量
                        $useCoinNum = $effMin * $unitPrice; // 本次连线 实际应收准币 数量
                    }
                    if ($rtcInfo['coin'] != $useCoinNum)
                    {   // 如果多扣费了 进行退费 或者 少扣了 进行补扣
                        $diffCoin = $rtcInfo['coin'] - $useCoinNum; // 获取 使用优惠后 需要更新的差值准币
                        $rtcInfoUpdate['coin'] = $useCoinNum;
                        $rtcInfo['coin'] = $useCoinNum;
                        $totalAmount = $useCoinNum / 10;
                        // 更新用户准币余额
                        $coinNum = $coinNum + $diffCoin;
                        $consume_price = $userCoin['consume_price'] + OrdersLib::getOrderCoinTotalAmount($diffCoin);
                        $consume_coin = $userCoin['consume_coin'] + $diffCoin;
                        //更新用户钱包金额
                        $UserAccountModel->UpdateData($rtcInfo['uid'], ['balance' => $coinNum, 'consume_price' => $consume_price, 'consume_coin' => $consume_coin, 'update_time' => time()], ['uid' => $rtcInfo['uid']]);
                    }
                }
                // 打点数据
                $eventMarkingData['coin_used'] = $useCoinNum;
            }
            $astrInfo = (new ZlcrAstr())->getInfoById($rtcInfo['astr_id']);
            $teamId = $astrInfo['team_id'] ?? 0;
            if ($useCoinNum > 0 || $giftRtcPrice > 0)    // 本次连线有收益 或者 咨询师有礼包收益
            {
                if ($useCoinNum > 0)
                {   // 写入 用户 准币流水
                    $insertData = [
                        'status' => 1,
                        'account' => 0,
                        'uid' => $rtcInfo['uid'],
                        'consumer_type' => 2,
                        'order_type' => 100,
                        'gid' => 0,
                        'pray_date' => 0,
                        'total_amount' => $totalAmount,
                        'coin_num' => $rtcInfo['coin'],
                        'balance' => $coinNum,
                        'order_id' => '',
                        'trade_type' => 4,
                        'create_time' => $nowTime,
                        'extend' => json_encode(['rtc_id' => $rtcInfo['id']], JSON_UNESCAPED_UNICODE),
                    ];
                    //增加准币明细记录
                    $UserAccountRecordModel->SaveData($rtcInfo['uid'], $insertData);
                }
                // 写入占星师 收入
                // 1、 计算咨询师收益 连线 （准币收益 + 连线礼包收益）* 收益百分比
                $totalPrice = (($rtcInfo['coin'] + $giftRtcPrice) * $rtcInfo['extend']['percent']) / 10;
                $earnings = Util::getAfterTaxAmount($totalPrice);
                // 2、 写入收益记录
                (new ZlcrAstrAccount())->astrRtcConsultEarningsSend([
                    'earning' => $earnings,
                    'total_amount' => $totalAmount, // 用户支付 时间金额
                    'astr_id' => $rtcInfo['astr_id'],
                    'type' => 1,    // 1=>入账 2=>提现 3=>后台人员回复的用户内容 4=>问答冻结  5=>问答解冻
                    'gid' => $rtcInfo['id'],
                    'proportion' => $rtcInfo['extend']['percent'],
                    'service_duration' => $rtcInfoUpdate['duration'],
                    'team_id' => $teamId,
                ], $appType);
                $isCustomer = true;
            } else
            {   // 本次收益0  没有计费时长
                $earnings = 0;
            }
            (new ZyhsConsultAstrData())->analysisDataUpdate($rtcInfo['astr_id'], (int)date('YmdH'), [
                'service_duration' => Db::raw("service_duration +" . $rtcInfoUpdate['duration']),
                'service_num' => Db::raw("service_num + 1"),
            ]);
            $rtcInfoUpdate['extend']['team_id'] = $teamId;
            $rtcInfoUpdate['astr_earning'] = $earnings;
            // 计算连线时长 分钟
            $levelScore = floor($rtcInfoUpdate['duration'] / 60);   // 连线时长 分钟 向下取整
            if ($levelScore > 0)
            {   // 更新咨询师 等级能力分
                $zlcr3ConsultAccountModel->changeAstrLevelScore($consultAccountInfo, $rtcInfo['id'], 1, $levelScore, 5);
            }

            if ($appType === 2 && Util::checkAppVersion('2.15.0', $rtcInfo['extend']['version'] ?? '1.0.0') !== '小' && $rtcInfoUpdate['duration'] >= 300)
            {   //  准了APP 连线时长 大于5分钟
                (new ZyhsConsultChatRecordDetails())->saveGetGiftData($chatDetail['chat_id'], $astrInfo, $rtcInfo['uid'], $appType);
            }
        }
        //  删除用户 连线咨询 时长信息缓存
        CacheManageZyhs::getInstance()->setCacheConfig($this->cacheModel)->setCacheKeyDetail('user_rtc_duration_data', $appType . ':' . $rtcInfo['uid'])->rmCache('user_rtc_duration_data');
        // 更新了连麦状态
        $this->updateData($rtcInfo['id'], $appType, $rtcInfo['uid'], $rtcInfoUpdate, 2);
        // 获取用户当前连麦 状态
        $userNowConsultRtcInfo = $this->getNowRtcDataByCache(1, $appType, $rtcInfo['uid']);
        if ($userNowConsultRtcInfo && $userNowConsultRtcInfo['chat_id'] == $chatDetailId)
        {   // 用户当前连麦 是 与当前取消是一致的
            $this->delNowRtcDataByCache(1, $appType, $rtcInfo['uid'], $chatDetailId); // 删除当前连麦信息
        }
        $astrTip = '';
        switch ($rtcInfoUpdate['status'])  //  4=>连麦结束 5=>故障挂断 6=>取消连麦（连接中挂断）
        {
            case 4:
                $durationTime = Util::secondToMinute($rtcInfoUpdate['duration']);
                $astrTip = "连线时长 {$durationTime}，收益{$rtcInfoUpdate['astr_earning']}元";
                $consultInfo = [
                    'status' => 4,
                    'tip' => "连线时长 {$durationTime}，消耗{$rtcInfo['coin']}准币",
                    'target' => 'local',
                    'link' => "rtc_consult_detail?id={$chatDetailId}&need_auth=2",
                ];
                $ud = [
                    'consult_num' => $this->raw('consult_num +1'), // 有效 咨询次数 +1
                    'last_consult_time' => $rtcInfo['start_time'], // 最后一次有效 咨询 开始 连麦时间
                    'last_chat_detail_time' => $nowTime, //
                ];
                if ($rtcInfo['coin'] > 0)
                {   // 本次连线 消耗了准币
                    // 用户咨询次数 信息  有付费情况才算有效咨询
                    (new ZyhsUserConsultInfo())->updateData($appType, $rtcInfo['uid'], [
                        'num' => 0,
                        'service_num' => $this->raw('service_num +1'), // 有效 咨询次数 +1
                        'last_service_time' => $nowTime,
                    ]);
                    $ud['consult_coin'] = $this->raw('consult_coin +' . $rtcInfo['coin']);// 消耗准币数
                }
                if ($isCustomer)
                {
                    $ud['is_customer'] = 1;
                }
                (new ZyhsConsultChatRecordAstr())->astroSendUpdate($appType, $rtcInfo['uid'], $rtcInfo['astr_id'], $ud);
                break;
            case 5:
                $consultInfo = [
                    'status' => 4,
                    'tip' => '故障挂断',
                    'target' => 'local',
                    'link' => 'empty',
                ];
                break;
            default:
                $consultInfo = [
                    'status' => 4,
//                    'tip' => $userType === 1 ? '连线已取消' : '咨询师不便接听，稍后重试',
                    'tip' => '连线已取消',
                    'target' => 'local',
                    'link' => 'empty',
                ];
        }

        $msgData1 = [
            'id' => $chatDetailId,
            'type' => 1,
            'time_des' => '',
            'time' => '',
            'avatar' => $userInfo['avatar'],
            'msg_des' => '连线咨询',
            'tags' => [],
            'consult_info' => $consultInfo,
            'btn_info' => null,
            'content' => '',
            'content_type' => 1,
            'astr_info' => null,
            'appointment_info' => null,
            'plugins_info' => null,
        ];

        if ($userType === 2 || ($userType === 1 && in_array($hangUpType, [2, 3], true)))
        {   // 向 用户 发送消息
            if ($rtcInfoUpdate['status'] !== 6)
            {   // 不是取消连麦的情况
                // 向 用户 发送 打点消息
                LiveMessage::sendMsg(LiveMessage::who($websocketWho, 0, $astrNowConsultRtcInfo['uid']), LiveMessage::MSG_TYPE_POP_CONSULT_CLOSE_EVENT_MARKING, $eventMarkingData);
            }
            // 1 连麦消息
            LiveMessage::sendMsg(LiveMessage::who($websocketWho, 0, $astrNowConsultRtcInfo['uid']), LiveMessage::MSG_TYPE_POP_CONSULT_MSG, [
                'msg_type' => 1,
                'astr_id' => $rtcInfo['astr_id'],
                'msg_data' => $msgData1,
            ]);
            if ($rtcInfoUpdate['status'] === 4)
            {   // 结束连麦
                // 2 连麦状态刷新消息
                $consultDetailRefresh = [
                    'target' => 'local',
                    'link' => "alert_consult_question?id={$chatDetailId}&need_auth=2",
                    'force_open' => 1,
                ];
                LiveMessage::sendMsg(LiveMessage::who($websocketWho, 0, $astrNowConsultRtcInfo['uid']), LiveMessage::MSG_TYPE_POP_CONSULT_DETAIL_REFRESH, $consultDetailRefresh);
            } else
            {   // 故障挂断 ｜ 取消连线
                LiveMessage::sendMsg(LiveMessage::who($websocketWho, 0, $chatDetail['uid']), LiveMessage::MSG_TYPE_POP_CONSULT_TOAST, [
                    'content' => $rtcInfoUpdate['status'] === 5 ? '故障挂断，连线已取消' : '连接失败，连线已取消',
                ]);
            }
        }
        if ($rtcInfoUpdate['status'] === 6)
        {
            $consultInfo['tip'] = '连线已取消';
            $eventMarkingData = null;
        }
        if ($rtcInfoUpdate['status'] === 4)
        {
            $consultInfo['tip'] = $astrTip;
        }
        $msgData2 = [
            'id' => $chatDetailId,
            'type' => 2,
            'time_des' => '',
            'time' => '',
            'avatar' => $userInfo['avatar'],
            'msg_des' => '连线咨询',
            'tags' => [],
            'consult_info' => $consultInfo,
            'btn_info' => $rtcInfoUpdate['status'] === 4 ? [['name' => '查看记录', 'type' => 4, 'id' => $chatDetailId,]] : null,
            'content' => '',
            'content_type' => 1,
            'astr_info' => null,
            'appointment_info' => null,
            'plugins_info' => null,
        ];
        if ($userType === 1 || ($userType === 2 && in_array($hangUpType, [2, 3], true)))
        {   // 向咨询师 发送消息
            // 1 连麦消息
            LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_ASTRO, 0, $rtcInfo['astr_id']), LiveMessage::MSG_TYPE_POP_CONSULT_MSG, [
                'msg_type' => 2,
                'app_type' => $appType,
                'uid' => $rtcInfo['uid'],
                'msg_data' => $msgData2,
            ]);
            if ($rtcInfoUpdate['status'] === 4)
            {   // 结束连麦
                // 2 连麦状态刷新消息
                $consultDetailRefresh = [
                    'target' => 'local',
                    'link' => "alert_consult_question?id={$chatDetailId}&need_auth=2",
                    'force_open' => 1,
                ];
                LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_ASTRO, 0, $rtcInfo['astr_id']), LiveMessage::MSG_TYPE_POP_CONSULT_DETAIL_REFRESH, $consultDetailRefresh);
            } else
            {   // 故障挂断 ｜ 取消连线
                LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_ASTRO, 0, $rtcInfo['astr_id']), LiveMessage::MSG_TYPE_POP_CONSULT_TOAST, [
                    'content' => $rtcInfoUpdate['status'] === 5 ? '故障挂断，连线已取消' : '连接失败，连线已取消',
                ]);
            }
        }
        $this->loseOperatorLicense($chatDetailId, 'HangUp');

        return [
            'status' => true,
            'msg' => '',
            'data' => $userType === 1 ? $msgData1 : $msgData2,
            'event_marking_data' => $eventMarkingData,  // 返回 事件打点信息
        ];
    }

    /**
     * 获取 用户 连线咨询 RTC连线 时长
     * @param int $appType 1 =>准有好事 2=>准了APP
     * @param int $uid
     * @return int|int[]|mixed
     * @throws \Exception
     */
    public function getConsultRtcDurationMin(int $appType, int $uid = 0)
    {
        if (!$uid)
        {
            return 0;
        }

        $data = CacheManageZyhs::getInstance()->setCacheConfig($this->cacheModel)->setCacheKeyDetail('user_rtc_duration_data', $appType . ':' . $uid)
            ->setCacheTime(3600) // 缓存时间 1小时
            ->getDataAndSet(function () use ($appType, $uid)
            {
                try
                {
                    $d = $this->where(['app_type' => $appType, 'uid' => $uid, 'status' => 4])->column('duration,test_duration,eff_duration,coin', 'id');
                    $dd = [
                        'duration' => 0,            // 总连线时长 - 秒
                        'eff_duration' => 0,        // 总计费连线时长 - 秒
                        'duration_min' => 0,        // 总连线时长 - 分钟    【每条记录的分钟数之和】
                        'eff_duration_min' => 0,    // 总计费连线时长 - 分钟 【每条记录的分钟数之和】
                        'num' => 0,
                        'coin' => 0,    // 消耗时长
                    ];
                    foreach ($d as $item)
                    {
                        $dd['duration'] += $item['duration'];
                        $dd['eff_duration'] += $item['eff_duration'];
                        $dd['duration_min'] += (int)ceil(($item['duration'] / 60));
                        $dd['eff_duration_min'] += (int)ceil(($item['eff_duration'] / 60));
                        $dd['num']++;
                        $dd['coin'] += $item['coin'];
                    }
                    return $dd;
                }
                catch (\Exception $e)
                {
                    return [];
                }
            }, [], 'user_rtc_duration_data');

        if ($data)
        {
            return arrayKeyData2int($data, ['duration', 'eff_duration', 'duration_min', 'eff_duration_min', 'num', 'coin']);
        } else
        {
            return [
                'duration' => 0,
                'eff_duration' => 0,
                'duration_min' => 0,
                'eff_duration_min' => 0,
                'num' => 0,
                'coin' => 0,
            ];
        }
    }
}
